/*
 * MyGWT User Extensions
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.mygwt.ux.client.widgets;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.mygwt.ux.client.event.ValueChangeEvent;
import net.mygwt.ux.client.event.ValueChangeListener;
import net.mygwt.ux.client.widgets.impl.TextBoxImpl;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;

/**
 * Extends the default GWT TextBox. It can be used as a direct replacement to
 * GWT TextBox.
 * 
 * The enhanced capabilities include the possibility to have monocase field and
 * a password field with the same possibilities as a regular text field.
 * 
 * @author Damien Ferrand
 */
public class TextBox extends com.google.gwt.user.client.ui.TextBox {
	/**
	 * Style for a default TextBox.
	 */
	public static final int NONE = 0;
	/**
	 * Style for a TextBox without lower case characters.
	 */
	public static final int UPPERCASE = 1;
	/**
	 * Style for a password field.
	 */
	public static final int PASSWORD = 2;
	/**
	 * Style for a TextBox without upper case characters.
	 */
	public static final int LOWERCASE = 4;
	/**
	 * The style of the TextBox.
	 */
	private int style;
	/**
	 * The browser specific implementation object.
	 */
	private TextBoxImpl impl;
	/**
	 * The list of ValueChangeListener listeners.
	 */
	private List valueChangeListeners;
	/**
	 * Contains the previous value of the text box.
	 */
	private String previousValue = "";

	/**
	 * Create a text box without maximum length and without style.
	 */
	public TextBox() {
		this(0, NONE);
	}

	/**
	 * Creates a text box with a given size and style.
	 * 
	 * If size is not 0, it will set <strong>both</strong> the maximum length
	 * and the visible length.
	 * 
	 * @param size
	 *            the maximum and visible length of the TextBox. 0 for no
	 *            maximum and default visible length
	 * @param style
	 *            the styles to apply to the TextBox
	 */
	public TextBox(int size, int styleParm) {
		super();

		impl = (TextBoxImpl) GWT.create(TextBoxImpl.class);
		impl.setTextBox(this);

		this.style = styleParm;

		if (size != 0) {
			setMaxLength(size);
			setVisibleLength(size);
		}

		if ((style & PASSWORD) == PASSWORD) {
			setType(getElement(), "password");
			setStyleName("gwt-PasswordTextBox");
		}

		// Set the implementation specific style code
		impl.applyStyle();

		valueChangeListeners = new ArrayList();
	}

	/**
	 * Changes the type of a DOM element.
	 * 
	 * @param e
	 *            the element
	 * @param type
	 *            the new type
	 */
	private void setType(Element e, String type) {
		DOM.setElementProperty(e, "type", type);
	};

	/**
	 * Set the TextBox text. Enforces UPPERCASE or LOWERCASE style.
	 * 
	 * @see com.google.gwt.user.client.ui.TextBoxBase#setText(java.lang.String)
	 */
	public void setText(String text) {
		String textToSet = text;

		if ((style & UPPERCASE) == UPPERCASE) {
			textToSet = text.toUpperCase();
		}

		if ((style & LOWERCASE) == LOWERCASE) {
			textToSet = text.toLowerCase();
		}
		super.setText(textToSet);
		previousValue = textToSet;
	}

	/**
	 * Get the style value.
	 * 
	 * @return the style value.
	 */
	public int getStyle() {
		return style;
	}

	/**
	 * Registers a new ValueChangeListener.
	 * 
	 * @param valueChangeListener
	 *            the ValueChangeListener object.
	 */
	public void addValueChangeListener(ValueChangeListener valueChangeListener) {
		valueChangeListeners.add(valueChangeListener);
	}

	public void checkValueChange(String previousValue, String newValue) {
		if (!previousValue.equals(newValue)) {
			final ValueChangeEvent vce = new ValueChangeEvent(getElement(),
					previousValue, newValue);
			DeferredCommand.addCommand(new Command() {
				public void execute() {
					fireValueChangeEvent(vce);
				}
			});
		}
	}

	/**
	 * Fire a ValueChangeEvent.
	 * @param valueChangeEvent the ValueChangeEvent object.
	 */
	private void fireValueChangeEvent(ValueChangeEvent valueChangeEvent) {
		Iterator it = valueChangeListeners.iterator();
		while (it.hasNext()) {
			ValueChangeListener vcl = (ValueChangeListener) it.next();
			vcl.valueChanged(valueChangeEvent);
		}
	}

	/**
	 * Gets the previous value of the text box.
	 * @return the previous value of the text box.
	 */
	public String getPreviousValue() {
		return previousValue;
	}

	/**
	 * This will update the previous value of the text box with the current value.
	 */
	public void updatePreviousValue() {
		previousValue = getText();
	}
}
